/**
 * @file Persister.cpp
 * @brief 持久化存储实现
 * 
 * 负责 Raft 状态和快照的持久化存储
 * 提供读写 Raft 状态、快照数据的接口
 * 确保数据在节点重启后能够正确恢复
 */
#include "Persister.h"
#include "util.h"

// Save - 保存 Raft 状态和快照
// 将 Raft 状态和快照数据同时写入持久化存储
// todo:会涉及反复打开文件的操作，没有考虑如果文件出现问题会怎么办？？
void Persister::Save(const std::string raftstate, const std::string snapshot) {
  std::lock_guard<std::mutex> lg(m_mtx);
  clearRaftStateAndSnapshot();  // 清空现有数据
  // 将raftstate和snapshot写入本地文件
  m_raftStateOutStream << raftstate;  // 写入 Raft 状态
  m_snapshotOutStream << snapshot;    // 写入快照数据
}

// ReadSnapshot - 读取快照数据
// 从持久化存储中读取快照数据
std::string Persister::ReadSnapshot() {
  std::lock_guard<std::mutex> lg(m_mtx);
  if (m_snapshotOutStream.is_open()) {
    m_snapshotOutStream.close();  // 关闭输出流以确保数据写入
  }

  DEFER {
    m_snapshotOutStream.open(m_snapshotFileName);  //默认是追加
  };
  std::fstream ifs(m_snapshotFileName, std::ios_base::in);
  if (!ifs.good()) {
    return "";  // 文件不存在或无法读取
  }
  std::string snapshot;
  ifs >> snapshot;  // 读取快照数据
  ifs.close();
  return snapshot;
}

// SaveRaftState - 保存 Raft 状态
// 仅保存 Raft 状态数据，不影响快照
void Persister::SaveRaftState(const std::string &data) {
  std::lock_guard<std::mutex> lg(m_mtx);
  // 将raftstate和snapshot写入本地文件
  clearRaftState();  // 清空现有 Raft 状态
  m_raftStateOutStream << data;  // 写入新的 Raft 状态
  m_raftStateSize += data.size();  // 更新状态大小
}

// RaftStateSize - 获取 Raft 状态大小
// 返回当前 Raft 状态数据的大小（字节数）
long long Persister::RaftStateSize() {
  std::lock_guard<std::mutex> lg(m_mtx);

  return m_raftStateSize;
}

// ReadRaftState - 读取 Raft 状态
// 从持久化存储中读取 Raft 状态数据
std::string Persister::ReadRaftState() {
  std::lock_guard<std::mutex> lg(m_mtx);

  std::fstream ifs(m_raftStateFileName, std::ios_base::in);
  if (!ifs.good()) {
    return "";  // 文件不存在或无法读取
  }
  std::string snapshot;
  ifs >> snapshot;  // 读取状态数据
  ifs.close();
  return snapshot;
}

// Persister 构造函数 - 初始化持久化存储
// 创建并初始化用于存储 Raft 状态和快照的文件
Persister::Persister(const int me)
    : m_raftStateFileName("raftstatePersist" + std::to_string(me) + ".txt"),
      m_snapshotFileName("snapshotPersist" + std::to_string(me) + ".txt"),
      m_raftStateSize(0) {
  /**
   * 检查文件状态并清空文件
   */
  bool fileOpenFlag = true;
  std::fstream file(m_raftStateFileName, std::ios::out | std::ios::trunc);
  if (file.is_open()) {
    file.close();
  } else {
    fileOpenFlag = false;
  }
  file = std::fstream(m_snapshotFileName, std::ios::out | std::ios::trunc);
  if (file.is_open()) {
    file.close();
  } else {
    fileOpenFlag = false;
  }
  if (!fileOpenFlag) {
    DPrintf("[func-Persister::Persister] file open error");
  }
  /**
   * 绑定流
   */
  m_raftStateOutStream.open(m_raftStateFileName);  // 打开 Raft 状态文件流
  m_snapshotOutStream.open(m_snapshotFileName);    // 打开快照文件流
}

// Persister 析构函数 - 清理资源
// 关闭所有打开的文件流
Persister::~Persister() {
  if (m_raftStateOutStream.is_open()) {
    m_raftStateOutStream.close();
  }
  if (m_snapshotOutStream.is_open()) {
    m_snapshotOutStream.close();
  }
}

// clearRaftState - 清空 Raft 状态
// 清空 Raft 状态文件内容并重置大小计数器
void Persister::clearRaftState() {
  m_raftStateSize = 0;  // 重置大小计数器
  // 关闭文件流
  if (m_raftStateOutStream.is_open()) {
    m_raftStateOutStream.close();
  }
  // 重新打开文件流并清空文件内容
  m_raftStateOutStream.open(m_raftStateFileName, std::ios::out | std::ios::trunc);
}

// clearSnapshot - 清空快照
// 清空快照文件内容
void Persister::clearSnapshot() {
  if (m_snapshotOutStream.is_open()) {
    m_snapshotOutStream.close();
  }
  m_snapshotOutStream.open(m_snapshotFileName, std::ios::out | std::ios::trunc);
}

// clearRaftStateAndSnapshot - 清空 Raft 状态和快照
// 同时清空 Raft 状态和快照文件内容
void Persister::clearRaftStateAndSnapshot() {
  clearRaftState();   // 清空 Raft 状态
  clearSnapshot();    // 清空快照
}
